package com.tyk.bookstore.back.message.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tyk.bookstore.back.common.core.model.result.CommonResultEnum;
import com.tyk.bookstore.back.common.core.util.AssertUtil;
import com.tyk.bookstore.back.common.core.util.IdGenerator;
import com.tyk.bookstore.back.common.core.util.ObjUtil;
import com.tyk.bookstore.back.common.mq.RabbitManager;
import com.tyk.bookstore.back.common.security.util.SecurityUtil;
import com.tyk.bookstore.back.message.model.entity.InfoNoticeDo;
import com.tyk.bookstore.back.message.model.enume.NoticeState;
import com.tyk.bookstore.back.message.model.query.InfoNoticeAddQuery;
import com.tyk.bookstore.back.message.model.query.InfoNoticePageQuery;
import com.tyk.bookstore.back.message.model.query.InfoNoticeUpdateQuery;
import com.tyk.bookstore.back.message.model.result.InfoNoticeResultEnum;
import com.tyk.bookstore.back.message.model.vo.InfoNoticePageVo;
import com.tyk.bookstore.back.message.model.vo.InfoNoticeVo;
import com.tyk.bookstore.back.message.mq.NoticeMqConstant;
import com.tyk.bookstore.back.message.repository.InfoNoticeRepository;
import com.tyk.bookstore.back.message.service.InfoNoticeService;
import com.tyk.bookstore.back.message.util.MapStructMessage;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;

/**
 * @author tyk
 * @description 消息通知管理
 */
@Service
@RequiredArgsConstructor
public class InfoNoticeServiceImp implements InfoNoticeService {
    private final InfoNoticeRepository infoNoticeRepository;
    private final MapStructMessage mapStructMessage;
    private final RabbitManager rabbitManager;


    @Override
    public InfoNoticeVo getById(Long id) {
        InfoNoticeDo notice = infoNoticeRepository.selectById(id);
        AssertUtil.notNull(notice, InfoNoticeResultEnum.NOTICE_NOT_FOUND);
        return mapStructMessage.toInfoNoticeVo(notice);
    }

    @Override
    public InfoNoticePageVo getPage(InfoNoticePageQuery query) {
        Page<InfoNoticeDo> page = new Page<>(query.getPage(), query.getLimit());
        LambdaQueryWrapper<InfoNoticeDo> w = buildPageQueryWrapper(query);
        infoNoticeRepository.selectPage(page, w);
        return mapStructMessage.toInfoNoticePageVo(page);
    }


    @Override
    public void add(InfoNoticeAddQuery query) {

        long userId = SecurityUtil.getLoginId();

        // 关联字段校验
        boolean f = ObjUtil.equal(query.getState(), NoticeState.ON) && ObjUtil.equal(query.getTimedRelease(), true);
        if (f) {
            AssertUtil.notNull(query.getReleaseTime(), CommonResultEnum.PARAM_ERROR);
            query.setState(NoticeState.OFF);
        }

        // 插入数据库
        InfoNoticeDo ind = mapStructMessage.toInfoNoticeDo(query).setUserId(userId);
        ind.setId(IdGenerator.id());
        infoNoticeRepository.insert(ind);

        // 定时发布
        if (f)
            rabbitManager.sendDelayMsg(
                    NoticeMqConstant.NOTICE_RELEASE_EXCHANGE,
                    NoticeMqConstant.NOTICE_INFO_RELEASE_ROUTING,
                    ind.getId(),
                    Duration.between(LocalDateTime.now(), query.getReleaseTime()).getSeconds()
            );

    }

    @Override
    public void updateById(InfoNoticeUpdateQuery query) {

        // 关联字段校验
        boolean f = ObjUtil.equal(query.getState(), NoticeState.ON) && ObjUtil.equal(query.getTimedRelease(), true);
        if (f) {
            AssertUtil.notNull(query.getReleaseTime(), CommonResultEnum.PARAM_ERROR);
            query.setTimedRelease(false);
        }

        // 通知存在
        AssertUtil.isTrue(
                infoNoticeRepository.exist1Eq(
                        InfoNoticeDo::getId, query.getId(), InfoNoticeDo.class
                ),
                InfoNoticeResultEnum.NOTICE_NOT_FOUND
        );

        // 更新
        InfoNoticeDo ind = mapStructMessage.toInfoNoticeDo(query).setUserId(0L);
        infoNoticeRepository.updateById(ind);

        // 定时发布
        rabbitManager.sendDelayMsg(
                NoticeMqConstant.NOTICE_RELEASE_EXCHANGE,
                NoticeMqConstant.NOTICE_INFO_RELEASE_ROUTING,
                ind.getId(),
                Duration.between(LocalDateTime.now(), query.getReleaseTime()).getSeconds()
        );
    }

    @Override
    public void deleteById(Long id) {
        AssertUtil.isTrue(
                infoNoticeRepository.exist1Eq(
                        InfoNoticeDo::getId, id, InfoNoticeDo.class
                ),
                InfoNoticeResultEnum.NOTICE_NOT_FOUND
        );
        infoNoticeRepository.deleteById(id);
    }

    @Override
    public void changeState(Long id, NoticeState state) {
        AssertUtil.isTrue(
                infoNoticeRepository.exist1Eq(
                        InfoNoticeDo::getId, id, InfoNoticeDo.class
                ),
                InfoNoticeResultEnum.NOTICE_NOT_FOUND
        );
        infoNoticeRepository.update1Set1Eq(
                InfoNoticeDo::getState, NoticeState.ON,
                InfoNoticeDo::getId, id,
                InfoNoticeDo.class
        );
    }

    /**
     * 构建通知分页查询条件
     */
    private LambdaQueryWrapper<InfoNoticeDo> buildPageQueryWrapper(InfoNoticePageQuery query) {

        LambdaQueryWrapper<InfoNoticeDo> w = Wrappers.lambdaQuery(InfoNoticeDo.class);

        w.like(ObjUtil.notBlank(query.getTitle()), InfoNoticeDo::getTitle, query.getTitle());

        w.like(ObjUtil.notBlank(query.getKeyword()), InfoNoticeDo::getContent, query.getKeyword());

        w.like(ObjUtil.notBlank(query.getSignature()), InfoNoticeDo::getSignature, query.getSignature());

        w.ge(query.getCreateTimeFrom() != null, InfoNoticeDo::getCreateTime, query.getCreateTimeFrom());
        w.le(query.getCreateTimeTo() != null, InfoNoticeDo::getCreateTime, query.getCreateTimeTo());

        w.orderBy(true, false, InfoNoticeDo::getCreateTime);

        return w;
    }

}
